<?php

/*
 * Coupyright @ 2012. Mirza Adipradhana
 * 
 * Class untuk user logged, seperti login, logout dsb.
 * 
 * KETENTUAN:
 * Username harus diset pada class
 * 
 * ERROR HANDLING:
 * ** User yang mendirect langsung ke halaman login.php (dimana ekskusi Login() dilakukan):
 *    - UNLOGGED USER
 *      Unlogged user dianggap sebagai user yang berusaha login. Jika user tsb tidak memiliki username atau password maka dianggap user tidak exist atau password salah.
 * 
 * ** User yang mendirect langsung ke halaman activation.php (tempat aktivasi user):
 *    - UNLOGGED USER
 *      Setiap melakukan pembuatan class Logged, otomatis mengeksekusi method LoggedInfo(), dimana method tersebut memilah apakah user telah LoggedIn atau belum. Jika sudah, diperiksa validitasnya.
 *      Pada activation.php telah diterapkan method SetUserLevel() yang bernilai true (artinya untuk mengakses halaman tersebut user harus melewati autentikasi (logged in)), dengan begitu user yang belum terautentikasi secara otomatis akan di redirect ke halaman login page jika mengakses halaman ini.
 * 
 * 
 * 
 */

class Logged {

    protected $mSession;
    //private $mSessionConfig;
    protected $mIsLoggedIn = false;
    protected $mIsLoginSucces = false;
    protected $mLoginAttempt = 0;
    protected $mUser;
    protected $mUserId;
    protected $mUsername;
    protected $mPassword;
    protected $mHashPassword;
    protected $mSalt;
    protected $mLevel;
    protected $mValiditas;
    protected $mIsDeveloperLogin = false;
    //ERROR HANDLER
    protected $mError = false;
    protected $mErrorMessage = array("ERROR_SECTION" => "AUTH", "ERROR_CODE");

    public function __construct($mSession) {
        //print_r($_SESSIONHANDLER);
        $this->mSession = $mSession;

        $this->LoggedInfo();
    }

    protected function LoggedInfo() {
        //CHECK Info Login User: dilihat dari apakah $tSession user isset?
        //Jika isset, verifikasi kebenaran SESSION, jika unvalid lakukan destroy session
        //Jika tidak maka IsLoggedIn = false
        if (isset($this->mSession->mVars[User])) {
            //CHECK: Jika WEBMASTER maka monggo
            //echo '<h3>LOGGED INFO</h3>';
            //print_r($this->mSession->mVars[User]);
            //echo 'UID: '.$this->mSession->mVars[User][Id].'<br>Username'.$this->mSession->mVars[User][Username].'<br>LEVEL: '.$this->mSession->mVars[User][Level];
            if (($this->mSession->mVars[User][Id] == "wbmstr" && $this->mSession->mVars[User][Username] == "wbmstr" && $this->mSession->mVars[User][Level] == 168)) {
                $this->mIsLoggedIn = true;
                $this->mIsDeveloperLogin = true;
                $this->mLevel = 168;
            } else {
                //VERIFIKASI KEBENARAN SESSION, apakah user exist?
                $tValidasi = false;
                $mQuery = new DBQueryParse();
                $tSQL = "SELECT username, level, validitas, salt, person_id FROM app_user WHERE username='" . $this->mSession->mVars[User][Username] . "' ";
                //echo $tSQL.'<br>';
                $tRes = $mQuery->Execute($tSQL);
                if ($tRes->Count() == 1) {
                    $tValidasi = true;
                    if ($tRes->MoveNext()) {
                        $this->mUsername = $tRes->username;
                        $this->mLevel = $tRes->level;
                        $this->mValiditas = $tRes->validitas;
                        $this->mSalt = $tRes->salt;
                    }

                    //EKSEKUSI LANJUTAN
                    if ($tValidasi) {
                        $this->mIsLoggedIn = true;
                    } else {
                        $this->mIsLoggedIn = false;
                        $this->mError = 4;
                        $this->mErrorMessage[ERROR_CODE] = "USER_VALIDITY";

                        $this->LoginResult("index.php");

                        $this->mSession->DestroySession(TRUE);
                        die();

                        //return false;
                    }
                } else {
                    $this->mIsLoggedIn = false;
                    $this->mSession->DestroySession(TRUE);
                    die();
                }
            }
        }
        else
            $this->mIsLoggedIn = false;
    }

    protected function LoginResult($pRedirectURL) {
        $tURL = $pRedirectURL;
        if ($this->mError !== false)
            $tURL = $pRedirectURL . '?err=' . $this->mError;
        header("Location: " . $tURL);
        exit;
    }

    public function SetLevelAccess($pLevel) {
        /*
         * DESKRIPSI:
         * TRUE -> must login
         * FALSE -> tidak
         * NUMBER ->Number of level, | separator
         * 
         */

        $tResult = false;

        //CHECK: Jika level otorisasi != true / nilai level
        //TRUE = ALL IN
        if ($this->mSession->mVars[User][Level] === 168 || $this->mSession->mVars[User][Level] === 9999) {
            $tResult = true;
        } else {
            if ($pLevel !== true && $pLevel !== false) {
                $tAuth = explode("|", $pLevel);
                $i = 0;
                while ($tAuth[$i] != "") {
                    if ($tAuth[$i] == $this->mSession->mVars[User][Level])
                        $tResult = true;
                    $i++;
                }
            }
            else if ($pLevel === true) {
                if ($this->mIsLoggedIn)
                    $tResult = true;
                else {
                    //IF: ketentuan true dan nilainya false maka langsung tendang ke halaman login
                    $tResult = false;
                    $this->LoginResult("index.php");
                }
            } else {
                $tResult = true;
            }
        }
        /* else if($pLevel === true && !$this->mIsLoggedIn) {
          //JIKA TRUE, minimal harus login, dan mIsLoggedIn False, maka redirect ke page login
          $mRedirect= new Redirector(LOGIN_PAGE);
          $mRedirect->Redirecting();
          die();
          } */
        return $tResult;
    }

    protected function GenerateSalt() {
        $tSalt = rand(0, 1028);
        return $tSalt;
    }

    public function GeneratePasswordHash($pSalt) {
        //echo '$this->GetUserId()= '.$this->GetUserId();
        //echo '<br>'.$this->GetUserId().'<br>'.$this->mPassword.'<br>salt= '.$pSalt.'<br>';
        $str = "Alfa7" . $this->GetUserId() . $this->mPassword . "SeesternIT" . $pSalt;
        return md5($str);
    }

    protected function CheckPassword() {
        /*
         * Pengecekan password berdasarkan Username yang diinputkan
         * DESKRIPSI ERROR:
         * 1: Wrong PWD
         * 2: User tidak exist: lakukan session destroy!
         * 3: User berstatus BLOCKED.
         */

        $tSQL = 'SELECT username, pwd, id_person, salt, validitas, level_id, status, nama_lengkap, level ';
        $tSQL.='FROM view_app_user WHERE username="' . $this->mUsername . '" ';
        //echo $tSQL;
        $tData = new DBQueryParse();
        $tResult = $tData->Execute($tSQL);

        //CHECK: apakah user ybs exist?
        if ($tResult->count() == 0 || $tResult->count() > 1) {
            $this->mError = 2;
            $this->mErrorMessage[ERROR_CODE] = "USER_UNEXIST";
            return false;
        } else {
            $tResult->MoveNext();
            //REGENERATE: Pssword hash dari yang terdapat di DB
            $this->mHashPassword = $this->GeneratePasswordHash($tResult->salt);

            if ($tResult->status == 2) {
                $this->mErrorMessage[ERROR_CODE] = "USER_BLOCKED";
                $this->mError = 3;
                return false;
            } else {
                //Jika password salah, redirect ke halaman login
                if ($this->mHashPassword != $tResult->pwd) {
                    $this->mError = 1;
                    $this->mErrorMessage[ERROR_CODE] = "USERNAME_PWD_WRONG";
                    return false;
                } else {
                    //berhasil
                    return true;
                }
            }
        }
    }

    protected function CheckValiditasUser($pUsername, $pUserId, $pLevel, $pSalt) {
        $tStr = 'Alfa7';
        $tStr.= $pLevel . $pUsername . $pUserId . $pSalt;
        $tStr.= 'SeesternIT';
        $tValiditas = crc32($tStr);
        $tValiditas = sprintf("%u", $tValiditas);

        return $tValiditas;
    }

    public function Login() {
        //CHECK: jika status login adalah tru maka proses login tidak dilakukan 2x
        //$tIsDeveloperLogin = false;
        if ($this->mIsLoggedIn === true) {
            //echo 'USERID :'.$tUserId.'<br>';
            $this->mUser = new CoreUser($this->mSession->mVars[User][Id]);
            $this->mIsLoginSucces = true;
        } else {
            //LOGIN ATTEMPT DIBATASI
            //Setiap percobaan login akan dicatat dan dibatasi sesuai batasan yang diset
            $this->mLoginAttempt++;
            $this->mIsLoginSucces = false;


            //VALIDASI NILAI INPUTAN LOGIN (username + password)
            //Jika tidak valid maka variabel akan bernilai FALSE, dan proses tidak dapat dilanjut
            if (!$this->mUsername || !$this->mPassword) {
                $this->mError = 1;
                $this->mErrorMessage[ERROR_CODE] = "USER_PWD_UNVALID";
                $this->LoginResult("index.php");
                die();
            } else {
                //SETUP PASSWORD HASH, berdasarkan Username yang sedang Logging In
                //CHECK: Hash password untuk DEVELOPER USER

                $this->mHashPassword = $this->GeneratePasswordHash(777);
                //echo $this->mHashPassword.' | '.APPLICATION_ROOT_PASSWORD;
                if ($this->mUsername == APPLICATION_ROOT_USERNAME && $this->mHashPassword == APPLICATION_ROOT_PASSWORD) {
                    $this->mIsLoginSucces = true;
                    $this->mIsDeveloperLogin = true;
                } else {
                    if ($this->CheckPassword()) {
                        //echo '<br>Checking password...OK';
                        //Retrieving User Detail
                        //echo '<br>Checking user status...';
                        $tUserId = $this->GetUserId();
                        $this->mUser = new CoreUser($tUserId);

                        //CHECK VALIDITAS USER
                        if ($this->CheckValiditasUser($this->mUsername, $tUserId, $this->mUser->GetLevel(), $this->mUser->GetSalt()) === $this->mUser->GetValiditas()) {
                            /*
                              echo '<br>User verification...OK';
                              echo '<br>Updating user log...OK';
                              echo '<br>Setting session...OK';
                             */

                            //LOGIN BERHASIL
                            $this->mIsLoginSucces = true;
                            $this->UpdateUserLoggedInformation();
                        } else {
                            //echo '<br>User verification...FAILED';
                            $this->mError = 4;
                            $this->mErrorMessage[ERROR_CODE] = "USER_VALIDITY";
                            $this->LoginResult("index.php");

                            $this->mSession->DestroySession(TRUE);
                            die();
                        }
                    } else {
                        $this->LoginResult("index.php");
                        //echo '<br>Checking password...FAILED';
                    }
                }
            }
        }

        //JIKA LOGIN SUCCESS, SETUP NEW SESSION
        if ($this->mIsLoginSucces) {
            $User = $this->SetupSession();
            $this->mSession->SetVar("User", $User);
            //print_r($this->mSession->mVars);
            //LOGIN REDIRECTING
            /*
              echo 'STATUS='.$this->mUser->GetStatus();
             */
            if ($this->mIsDeveloperLogin) {
                $this->LoginResult("main.php");
            } else {
                //CHECK: APAKAH STATUS NON-AKTIF
                if ($this->mUser->GetStatus() == 0) {
                    $this->LoginResult("activation.php");
                } else {
                    $this->LoginResult("main.php");
                }
            }
        }
    }

    public function SetupSession() {
        $tUser = array();

        //SET SESSION
        if ($this->mIsDeveloperLogin) {
            $tUser[Id] = 'wbmstr';
            $tUser[Username] = 'wbmstr';
            $tUser[Name] = 'Seestern IT';
            $tUser[Level] = 168;
            $tUser[Auth] = 'Developer';
            $tUser[Status] = 1;
        } else {
            $tUser[Id] = $this->mUser->GetUserId();
            $tUser[Username] = $this->mUser->GetUsername();
            $tUser[Name] = $this->mUser->GetNamaLengkap();
            $tUser[Level] = $this->mUser->GetLevel();
            $tUser[Auth] = $this->mUser->GetLevelNama();
            $tUser[Status] = $this->mUser->GetStatus();
        }
        //print_r($tUser);
        return $tUser;
    }

    protected function UpdateUserLoggedInformation() {
        $tData = new DBQueryExecute();
        $tSQL_UpdateLog = "UPDATE app_user SET login_l= '" . date("Y-m-d H:i:s") . "' WHERE username='$this->mUsername'";
        $tData->Execute($tSQL_UpdateLog);
    }

    public function Logout() {
        $this->mSession->DestroySession(TRUE);
    }

    protected function CreateSalt() {
        $tSalt = rand(0, 1028);
        return $tSalt;
    }

    /* ===== *//* ===== *//* ===== *//* ===== *//* ===== *//* ===== *//* ===== *//* ===== */

    // M U T U A T O R

    public function SetUserId($pPersonId) {
        $this->mUserId = $pPersonId;
    }

    public function SetUsername($pUsername) {
        $mInputValidation = new InputValidation();
        $mInputValidation->SetInput($pUsername);
        $mInputValidation->SetPattern(pUsername);

        $this->mUsername = $mInputValidation->CheckValidation();
    }

    public function SetPassword($pPassword) {
        $mInputValidation = new InputValidation();
        $mInputValidation->SetInput($pPassword);
        $mInputValidation->SetPattern(pPass);

        $this->mPassword = $mInputValidation->CheckValidation();
    }

    public function GetUserId() {
        if ($this->mUsername) {
            /*
             * Retrieve UserId berdasarkan username
             * Jika tidak ditemukan, periksa apakah UserId isset
             * Jika tidak juga, ERROR
             */
            $tSQL = 'SELECT id_person FROM view_app_user WHERE username="' . $this->mUsername . '" ';
            //echo $tSQL;
            $tData = new DBQueryParse();
            $tResult = $tData->Execute($tSQL);

            if ($tResult->Count() == 1) {
                $tResult->MoveNext();
                return $tResult->id_person;
            } else if ($this->mUserId) {
                return $this->mUserId;
            } else {
                return false;
                die();
            }
        } else {
            echo 'An error occured!';
            die();
        }
    }

}